﻿
//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#pragma once

#include "Vector3d.h"
#include "ElementId.h"
#include "ActionBase.h"
#include "ContainerUtil.h"

namespace gcmp
{
    class IDocument;
    class IElement;
    class IGraphicsNodeReference;
    class IUserTransaction;
    class PickResult;
    class IPickFilter;
    class IPickEvent;
    class IPickTarget;
}

namespace gcmp
{
    enum class GcmpEnPickStatus : int32_t
    {
        PS_NOTSTART = 0,
        PS_LBUTTON_DOWN = 1,
        PS_LBUTTON_UP = 2,
        PS_LBUTTON_MOVING = 4,
        PS_LBUTTON_DBCLK = 8
    };
}

namespace Sample
{
    class PickActionUtil
    {
    public:
        //在视图的给定屏幕位置做一次拾取操作，并更新全局的选择集
        static void UpdateCandidatesSingleton(gcmp::IUiView* pCurrentView,
            int screenX,
            int screenY,
            const gcmp::Vector3d& pos,
            const gcmp::IPickEvent* pPickPostProcesserEvent = nullptr,
            const gcmp::IPickFilter* pPickFilter = nullptr,
            const gcmp::IPickTarget* pPickTarget = nullptr,
            bool isPickingHighlightOnlyGraphicsNodeAllowed = false,
            bool selectByFaceInteriorEnabled = true,
            int pickTolerance = -1,
            bool isHoveringHighlight = true);
    };

    // 绘制线的动作。
    class SamplePickActionBase : public gcmp::ActionBase
    {
    public:
        SamplePickActionBase();
        virtual ~SamplePickActionBase();

        // 继承自IAction
    public: 
        virtual void InitAction(gcmp::IUiView* pCurrentView) override;

        virtual bool OnLButtonDown(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos) override;
        virtual bool OnLButtonUp(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos) override;
        virtual bool OnKeyDown(gcmp::IUiView* pCurrentView, int nChar) override;
        virtual bool OnMovePoint(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos) override;
        virtual bool OnLButtonDoubleClick(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos) override;

        virtual std::wstring GetPromptMessage() const override;

    public:
        void SetIsAllowedMove(bool IsAllowed) { m_isMoveAllowed = IsAllowed; }
        bool IsAllowedMove() const { return m_isMoveAllowed; }

        void SetIsPickingHighlightOnlyGraphicsNodeAllowed(bool IsAllowed) { m_isPickingHighlightOnlyGraphicsNodeAllowed = IsAllowed; }
        bool IsPickingHighlightOnlyGraphicsNodeAllowed() const { return m_isPickingHighlightOnlyGraphicsNodeAllowed; }

        bool IsSelectByFaceInteriorEnabled() const { return m_bSelectByFaceInteriorEnabled; }
        void SetSelectByFaceInteriorEnabled(bool enable) { m_bSelectByFaceInteriorEnabled = enable; }

        gcmp::IPickEvent* GetPickPostProcessEvent();
        const gcmp::IPickEvent* GetPickPostProcessEvent() const;
        void SetPickPostProcessEvent(gcmp::OwnerPtr<gcmp::IPickEvent> opPickPostProcessEvent);

        gcmp::IPickEvent* GetRectPickPostProcessEvent() { return m_opRectPickPostProcessEvent.get(); }
        const gcmp::IPickEvent* GetRectPickPostProcessEvent() const { return m_opRectPickPostProcessEvent.get(); }
        void SetRectPickPostProcessEvent(gcmp::OwnerPtr<gcmp::IPickEvent> opPickPostProcessEvent);

        gcmp::IPickTarget* GetPickTarget() { return m_pickTarget.get(); }
        void SetPickTarget(gcmp::OwnerPtr<gcmp::IPickTarget> pickTarget);

        gcmp::IPickFilter* GetPickFilter() { return m_upPickFilter.get(); }
        void SetPickFilter(gcmp::OwnerPtr<gcmp::IPickFilter>  opPickFilter);

        int GetPickPixelTolerance() { return m_pickPixelTolerance; }
        void SetPickPixelTolerance(int tolerance);

    protected:
        bool UpdateCandidates(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos);
        bool IsAuxiliaryElement(const gcmp::IDocument *pDoc, const gcmp::ElementId& id);

        //选择集变化时，给继承类处理的机会
        virtual void OnSelectionChanged();

        virtual void AddToSelection(gcmp::IDocument* pDocument, const gcmp::IGraphicsNodeReference& pickResult);

        virtual void AddToSelectionGroup(gcmp::IDocument* pDoc, gcmp::GraphicsNodeReferenceOwnerPtrSet& pickResults);

        virtual void ClearSelection(gcmp::IDocument* pDoc);

        virtual bool IsSelectionEmpty();

        virtual void ActionCancelled() override;

    protected:
        unsigned int          m_status;
        gcmp::Vector3d        m_startPt;
        gcmp::ElementId       m_auxElementId;//辅助对象Id

        int                   m_pickPixelTolerance;
        gcmp::OwnerPtr<gcmp::IPickTarget>  m_pickTarget;
        gcmp::OwnerPtr<gcmp::IPickFilter>  m_upPickFilter;

        gcmp::OwnerPtr<gcmp::IUserTransaction> m_upUserTransaction;
     
        gcmp::Vector3d m_worldStart;
        std::vector<gcmp::ElementId> m_selectRect;
        gcmp::ElementId m_rectangleSelectID;

        gcmp::OwnerPtr<gcmp::IPickEvent> m_opPickPostProcessEvent;
        gcmp::OwnerPtr<gcmp::IPickEvent> m_opRectPickPostProcessEvent;

        bool m_bSelectByFaceInteriorEnabled;

    private:
        gcmp::OwnerPtr<gcmp::IGraphicsElementShape> CreatSelectRectangleGrep(const gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos) const;

        void DrawSelectRectangle(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos, bool isIntersect);

        void DrawSelectRectangleInReplay(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos, bool isIntersect);

        void WorldToScreen(const gcmp::IUiView *pCurrentView, const gcmp::Vector3d &world, gcmp::Vector2d &screen) const;
        //进入编辑模式后，判断当前对象是否可以加入选择集
        bool IsCanBeSelect(gcmp::IDocument* pDoc, const gcmp::IGraphicsNodeReference& refAdd);

        //是否禁用拾取
        bool IsPickVisible();

        void UpdateHighlightOnlySelection();

        gcmp::GraphicsNodeReferenceOwnerPtrVector GetElementAssociatedCandidatesObjects(const gcmp::ElementId idElement);
        gcmp::GraphicsNodeReferenceOwnerPtrVector GetElementAssociatedSelectionObjects(const gcmp::ElementId idElement);

        std::wstring DisplayElementTriangleNumberOnStatusBar() const;

    private:
        bool m_isMoveAllowed = true; //是否允许拖拽element
        bool m_isPickingHighlightOnlyGraphicsNodeAllowed = false; //是否允许高亮可见的对象被pick到
        bool m_isHoveringHighlight = true; //是否支持略过高亮（默认支持，可以通过配置更改)；
        gcmp::IElement *m_pDebugDrawElement = nullptr;
    };

}

